package chabernac.gravidroid;

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import android.app.Activity;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.OnTouchListener;
import chabernac.android.draw.AbstractDrawable;
import chabernac.android.draw.PriorityThreadFactoryDecorator;
import chabernac.android.draw.SingleObjectQueue;
import chabernac.android.draw.SurfaceViewAnimation;
import chabernac.gravidroid.model.GravitySimulator;
import chabernac.gravidroid.model.LineForce;
import chabernac.gravidroid.model.Mass;
import chabernac.gravidroid.model.ParticleInteraction;
import chabernac.gravidroid.model.StructureFactory;
import chabernac.gravidroid.model.Vector;
import chabernac.gravidroid.paint.DrawableFactory;

public class GravidroidActivity extends Activity {
    @SuppressWarnings("deprecation")
    public class MySensorListener implements SensorEventListener {

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onSensorChanged(SensorEvent event) {
            // mySensorManager.getOrientation(R, values)
            // TODO Auto-generated method stub
        }
    }

    private final Random myRandom = new Random();
    /** Called when the activity is first created. */
    private ScheduledExecutorService myService = null;
    private GravitySimulator mySimulator = null;
    private SingleObjectQueue<AbstractDrawable> myDrawingQueue = null;
    private DrawableFactory myDrawableFactory = null;
    private SurfaceViewAnimation myView = null;
    private float x;
    private float y;
    private ScaleGestureDetector detector;

    private ParticleInteraction myParticleInteration = null;

    public GravidroidActivity() {
        // mySensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        // mySensor = mySensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        // mySensorManager.registerListener(new MySensorListener(), mySensor,
        // SensorManager.SENSOR_DELAY_NORMAL);

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        myView = (SurfaceViewAnimation) findViewById(R.id.animationview);
        myView.setOnTouchListener(new MyOnTouchListener());
        myDrawingQueue = myView.getDrawingQueue();

        mySimulator = new GravitySimulator();
        myParticleInteration = new ParticleInteraction(mySimulator);
        // theSimulator.addMass( new Mass().setLocation( new Vector( 50, 300
        // )).setMass( 1 ).setRadius( 5 ).setSpeed( new
        // Vector(200,0) ) );

        createLineForceAndSingleMass(mySimulator);
        // createLotsOfMasses();

        myDrawableFactory = new DrawableFactory(mySimulator);

        detector = new ScaleGestureDetector(this, new ScaleListener());

        start();
    }

    private void createLineForceAndSingleMass(GravitySimulator aSimulator) {
        Display display = getWindowManager().getDefaultDisplay();
        int maxSpeed = 100;

        Vector theGravity = new Vector(0,-1000);
        for (int x = 500; x < 4000; x += 600) {
            mySimulator.addMass(StructureFactory.createRectangle(new Vector(x, 500),
                                                                 new Vector(x + 500, 1000), Color.RED, theGravity, 2));
            
//            mySimulator.addMass(StructureFactory.createRectangle(new Vector(x, 1500),
//                                                                 new Vector(x + 500, 2000), Color.GREEN, theGravity, 2));
//            
//            mySimulator.addMass(StructureFactory.createRectangle(new Vector(x, 2500),
//                                                                 new Vector(x + 500, 3000), Color.BLUE, theGravity, 2));
        }

        //        mySimulator.addMass(StructureFactory.createRectangle(new Vector(500, 500), new Vector(1500, 1500), Color.RED, new Vector(1000, 0), 2));
        //        mySimulator
        //        .addMass(StructureFactory.createRectangle(new Vector(1600, 500), new Vector(2600, 1500), Color.RED, new Vector(-1000, 0), 2));

        // Mass theMass = new Mass().setLocation(new Vector(400,
        // 1000)).setMass(-200).setRadius(40).setCoreRadius(40).setMoveable(false);
        // mySimulator.addMass(theMass);
        //
        // theMass = new Mass().setLocation(new Vector(2700,
        // 1000)).setMass(-200).setRadius(40).setCoreRadius(40).setMoveable(false);
        // mySimulator.addMass(theMass);

        // mySimulator.addMass(StructureFactory.createTriangle(new Vector(500, 500),
        // 1000, 2, Color.RED, theGravity));
        // mySimulator.addMass(StructureFactory.createTriangle(new Vector(3000,
        // 500), 500, 2, Color.BLUE, theGravity));
        // mySimulator.addMass(StructureFactory.createTriangle(new Vector(500,
        // 5000), 800, 2, Color.GREEN, theGravity));
        // mySimulator.addMass(StructureFactory.createTriangle(new Vector(5000,
        // 5000), 800, 2, Color.MAGENTA, theGravity));
        // mySimulator.addMass(StructureFactory.createRectangle(new Vector(3000,
        // 500), 500, 2, Color.RED));
        // mySimulator.addMass(StructureFactory.createRectangle(new Vector(1500,
        // 500), 200, 2, Color.RED));

        // for (int i = 0; i < 10; i++) {
        // mySimulator.addMass(new Mass()
        // .setLocation(
        // new Vector(Math.abs(myRandom.nextInt() % (10 * display.getWidth())),
        // Math.abs(myRandom.nextInt() % (10 *
        // display.getHeight())))).setMass(10).setRadius(100).setCoreRadius(100)
        // .setColor(Color.GREEN)
        // // .setGravity( new Vector( 0, 1000 ) )
        // .setSpeed(new Vector(myRandom.nextInt() % maxSpeed, myRandom.nextInt() %
        // maxSpeed)));
        // }

        // Mass theMass1 = new Mass().setLocation( new Vector( Math.abs(
        // myRandom.nextInt() % ( 10 * display.getWidth() ) ), Math.abs( myRandom
        // .nextInt() %
        // ( 10 * display
        // .getHeight() ) ) ) )
        // .setMass( 2 )
        // .setRadius( 1 )
        // .setCoreRadius( 1 )
        // .setColor( Color.GREEN )
        // .setSpeed( new Vector( myRandom.nextInt() % maxSpeed, myRandom.nextInt()
        // % maxSpeed ) );
        //
        // Mass theMass2 = new Mass().setLocation( new Vector( Math.abs(
        // myRandom.nextInt() % ( 10 * display.getWidth() ) ), Math.abs( myRandom
        // .nextInt() %
        // ( 10 * display
        // .getHeight() ) ) ) )
        // .setMass( 2 )
        // .setRadius( 1 )
        // .setCoreRadius( 1 )
        // .setColor( Color.GREEN )
        // .setSpeed( new Vector( myRandom.nextInt() % maxSpeed, myRandom.nextInt()
        // % maxSpeed ) );
        //
        // mySimulator.addMass( new LinearMass( theMass1, theMass2, 3000, 1000, 100
        // ) );

        // theMass1 = new Mass()
        // .setLocation( new Vector( Math.abs(myRandom.nextInt() % (10 *
        // display.getWidth())), Math.abs(myRandom.nextInt() % (10 *
        // display.getHeight())) ))
        // .setMass( 2 )
        // .setRadius( 1 )
        // .setCoreRadius(1)
        // .setColor(Color.GREEN)
        // .setSpeed( new Vector(myRandom.nextInt() % maxSpeed,myRandom.nextInt() %
        // maxSpeed) ) ;
        //
        // theMass2 = new Mass()
        // .setLocation( new Vector( Math.abs(myRandom.nextInt() % (10 *
        // display.getWidth())), Math.abs(myRandom.nextInt() % (10 *
        // display.getHeight())) ))
        // .setMass( 2 )
        // .setRadius( 1)
        // .setCoreRadius(1)
        // .setColor(Color.GREEN)
        // .setSpeed( new Vector(myRandom.nextInt() % maxSpeed,myRandom.nextInt() %
        // maxSpeed) ) ;
        //
        // mySimulator.addMass(new LinearMass(theMass1, theMass2, 3000, 1000));

        mySimulator.addMass(new LineForce(new Vector(5, 5), new Vector(display.getWidth() * 10 - 5, 5), 100));
        mySimulator.addMass(new LineForce(new Vector(display.getWidth() * 10 - 5, 5), new Vector(display.getWidth() * 10 - 5, display
                                                                                                 .getHeight() * 10 - 1000), 100));
        mySimulator.addMass(new LineForce(new Vector(display.getWidth() * 10 - 5, display.getHeight() * 10 - 1000), new Vector(5, display
                                                                                                                               .getHeight() * 10 - 1000), 100));
        mySimulator.addMass(new LineForce(new Vector(5, display.getHeight() * 10 - 1000), new Vector(5, 5), 100));

    }

    private void start() {
        if (myService == null) {
            myView.start();
            PriorityThreadFactoryDecorator theThreadFactory = new
                    PriorityThreadFactoryDecorator(Executors.defaultThreadFactory());
            theThreadFactory.setPriority(Thread.NORM_PRIORITY);
            myService = Executors.newScheduledThreadPool(1, theThreadFactory);
            myService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        // long t1 = System.currentTimeMillis();
                        mySimulator.iterate();
                        if (myParticleInteration != null)
                            myParticleInteration.iterate();
                        // long t2 = System.currentTimeMillis();
                        // System.out.println("iteration took " + (t2-t1) + " ms");
                        // if(frameCounter++ % 10 == 0){
                        myDrawingQueue.put(myDrawableFactory.createDrawable());
                        // }
                    } catch (Exception e) {
                        Log.e("Scheduler", "error", e);
                    }
                }
            }, 0, 10, TimeUnit.MILLISECONDS);

        }
        // addTemporaryRepulsionMass(400, 1000);
    }

    private void addTemporaryRepulsionMass(float x, float y) {
        float[] thePoint = new float[] { x, y };
        myView.getTransformationMatrix().mapPoints(thePoint);
        final Mass theMass = new Mass()
        .setLocation(new Vector(thePoint[0], thePoint[1]))
        .setMass(-200)
        .setRadius(40)
        .setCoreRadius(40)
        .setMoveable(false);
        mySimulator.addMass(theMass);
        myService.schedule(new Runnable() {
            @Override
            public void run() {
                mySimulator.removeMass(theMass);
            }
        }, 500, TimeUnit.MILLISECONDS);

    }

    private void stop() {
        if (myService != null) {
            myView.stop();
            myService.shutdownNow();
            myService = null;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stop();
    }

    @Override
    protected void onPause() {
        super.onPause();
        stop();
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        start();
    }

    @Override
    protected void onResume() {
        super.onResume();
        start();
    }

    @Override
    protected void onStart() {
        super.onStart();
        start();
    }

    @Override
    protected void onStop() {
        super.onStop();
        stop();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            x = event.getX();
            y = event.getY();
            //            mySimulator.iterate();
            //            myDrawingQueue.put(myDrawableFactory.createDrawable());
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            float difx = event.getX() - x;
            float dify = event.getY() - y;
            myView.setTranslation(difx, dify);
            x = event.getX();
            y = event.getY();
        } else if (event.getAction() == MotionEvent.ACTION_POINTER_DOWN) {

        }
        detector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            myView.setScale(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY());
            return true;
        }
    }

    private class MyOnTouchListener implements OnTouchListener {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                addTemporaryRepulsionMass(event.getX(), event.getY());
            }
            return false;
        }

    }
}
